// 
// XmppContactTreeManager.cs
//
// Copyright © 2008 Paul Burton <paulburton89@gmail.com>
// Copyright © 2009 Jiří Zárevúcky <zarevucky.jiri@gmail.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//

using System;
using System.Text;

using GLib;
using Gdk;
using Gtk;

using Anculus.Core;

using Galaxium.Core;
using Galaxium.Gui;
using Galaxium.Gui.GtkGui;
using Galaxium.Client.GtkGui;

using Galaxium.Protocol.Xmpp.Library.Core;

namespace Galaxium.Protocol.Xmpp.GtkGui
{
	public class XmppContactTreeManager: BasicContactTreeManager
	{
		public override void RenderText (object data, CellRendererContact renderer)
		{
			if (!(data is XmppContact))
			{
				base.RenderText (data, renderer);
				return;
			}

			var status_format = "\n";
				//" <span foreground=\"#505050\" weight=\"light\"><i>({0})</i></span>\n";
			var status_format_compact = status_format;
			
			var contact = data as XmppContact;
		//	var session = contact.Session as XmppSession;
			
			var sb = new StringBuilder ();
			var detail = contact.Session.Account.DetailLevel;
			var config = Configuration.ContactList.Section;
			
			if (contact.Session.Account.UseDefaultListView)
			{
				var level = Configuration.ContactList.DetailLevel;
				detail = (ContactTreeDetailLevel) config.GetInt (level.Name, level.Default);
			}

			// Append contacts name
			sb.Append (Markup.EscapeText (contact.DisplayIdentifier));

			if (detail != ContactTreeDetailLevel.Compact)
			{
				// Append contacts status after name if roster mode allows it
				// TODO: settings to disable this
				sb.AppendFormat (status_format, contact.Presence.State);

				if (detail == ContactTreeDetailLevel.Detailed)
				{
					// Append the identifier of the contact
					//string name = contact.Transported ? contact.Jid.Node : contact.Jid;
					string name = contact.InternalContact.Jid;
					sb.AppendFormat ("<span size=\"small\">{0}</span>\n", Markup.EscapeText (name));
				}

				// TODO: settings for the roster modes
			}
			
			//if ((!contact.CurrentMedia.Enabled) || string.IsNullOrEmpty (contact.CurrentMedia.Display))
			//{ FIXME: what is/was this for?

			// Append contacts status message
			sb.Append ("<span foreground=\"#505050\" weight=\"light\" size=\"smaller\">");
			
			if (detail == ContactTreeDetailLevel.Compact)
				sb.Append (" ");
			
			bool showPersonalMessages = contact.Session.Account.UseDefaultListView
				? config.GetBool (Configuration.ContactList.ShowContactMessages.Name,
				                  Configuration.ContactList.ShowContactMessages.Default)
				: contact.Session.Account.ShowPersonalMessages;
			
			if (showPersonalMessages && !String.IsNullOrEmpty (contact.DisplayMessage)) {
				var str = TextUtility.ReplaceNewlinesWithSpaces (contact.DisplayMessage);
				sb.Append (Markup.EscapeText (str));
			} else
				sb.Append (""); // "No Personal Message"
			
			sb.Append ("</span>");
			//}
			
			/*else // TODO: extended states
			{
				string emot = string.Empty;
				
				if (EmoticonUtility.ActiveSet != null)
				{
					if (contact.CurrentMedia.Type == MsnCurrentMediaType.Music)
						emot = "(8)";
					else if (contact.CurrentMedia.Type == MsnCurrentMediaType.Games)
						emot = "(xx)";
					else if (contact.CurrentMedia.Type == MsnCurrentMediaType.Office)
						emot = "(co)";
				}
				
				sb.Append ("<span foreground=\"#505050\" weight=\"light\" size=\"smaller\">");
				sb.Append (Markup.EscapeText (emot + contact.CurrentMedia.Display + emot));
				sb.Append ("</span>");
			}*/

			if (detail == ContactTreeDetailLevel.Compact)
				sb.AppendFormat (status_format_compact, contact.Presence.State);
			
			renderer.ShowEmoticons = true;
			renderer.Markup = sb.ToString ();
		}

		private Pixbuf GetGeneralImage (XmppContact contact, IIconSize icon_size)
		{
			if (contact.Presence == XmppPresence.Away
			    || contact.Presence == XmppPresence.XA
			    || contact.Presence == XmppPresence.Unknown
			    || contact.Presence == XmppPresence.Error)
				return IconUtility.GetIcon ("galaxium-idle", icon_size);
			else if (contact.Presence == XmppPresence.Offline)
				return IconUtility.GetIcon ("galaxium-offline", icon_size);
			else
				return IconUtility.GetIcon ("galaxium-contact", icon_size);
		}

		private Pixbuf GetAvatarImage (XmppContact contact, ContactTreeDetailLevel detail)
		{
			var pixbuf = new Gdk.Pixbuf (contact.DisplayImage.ImageBuffer);
					
			if (contact.Presence == XmppPresence.Away
			    || contact.Presence == XmppPresence.XA
			    || contact.Presence == XmppPresence.Unknown
			    || contact.Presence == XmppPresence.Error
			    || contact.Presence == XmppPresence.Offline)
				return PixbufUtility.GetShadedPixbuf (pixbuf, detail);
			else
				return PixbufUtility.GetFramedPixbuf (pixbuf, detail);
		}
		
		public override void RenderLeftImage (object data, CellRendererPixbuf renderer)
		{
			if (!(data is XmppContact))
			{
				base.RenderLeftImage (data, renderer);
				return;
			}
			
			var contact = data as XmppContact;
			var detail_level = contact.Session.Account.DetailLevel;
			var config = Configuration.ContactList.Section;
			
			if (contact.Session.Account.UseDefaultListView)
			{
				var dlname = Configuration.ContactList.DetailLevel.Name;
				var dldefault = Configuration.ContactList.DetailLevel.Default;
				detail_level = (ContactTreeDetailLevel) config.GetInt (dlname, dldefault);
			}
			
			IIconSize icon_size = IconSizes.Other;
			Pixbuf pixbuf = null;
			
			switch (detail_level)
			{
				case ContactTreeDetailLevel.Compact:  icon_size = IconSizes.Small;  break;	
				case ContactTreeDetailLevel.Normal:   icon_size = IconSizes.Medium; break;	
				case ContactTreeDetailLevel.Detailed: icon_size = IconSizes.Large;  break;
				default: break; // not currently dealing with this size.
			}
			
			IActivity activity = GtkActivityUtility.PeekContactQueueItem(contact);
			
			// We are not in compact mode, so we need to use overlays now.
			if (detail_level == ContactTreeDetailLevel.Compact)
			{
				if (activity != null)
				{
					switch (activity.Type)
					{
						case ActivityTypes.Message:
							pixbuf = IconUtility.GetIcon ("galaxium-conversation-active", icon_size);
							break;
						case ActivityTypes.Transfer:
							pixbuf = IconUtility.GetIcon ("galaxium-transfer-receive", icon_size);
							break;
					}
				}
				else
				{
					pixbuf = XmppProtocolFactory.StatusLookup (contact.Presence, icon_size);
				}
			}
			else
			{
				bool show_display_images = contact.Session.Account.UseDefaultListView
					? config.GetBool (Configuration.ContactList.ShowContactImages.Name,
					                  Configuration.ContactList.ShowContactImages.Default)
					: contact.Session.Account.ShowDisplayImages;

				if (contact.DisplayImage != null && contact.DisplayImage.ImageBuffer != null
				    && show_display_images && !contact.SupressImage) {
					try { pixbuf = GetAvatarImage (contact, detail_level); }
					catch { pixbuf = GetGeneralImage (contact, icon_size); }
				} else {
					pixbuf = GetGeneralImage (contact, icon_size);
				}
				
				//if (contact.IsBlocked)
					//pixbuf = PixbufUtility.GetOverlayedRightPixbuf (pixbuf, IconUtility.GetIcon ("galaxium-status-block", IconSizes.Small));

			//	var pres = contact.Presence;

				if (contact.InternalContact.IsAsking || contact.InternalContact.IsWaiting) {
					var icon = IconUtility.GetIcon ("galaxium-status-reverse", IconSizes.Small);
					pixbuf = PixbufUtility.GetOverlayedLeftPixbuf (pixbuf, icon);
				}
				
				if (activity != null)
				{
					switch (activity.Type)
					{
						case ActivityTypes.Message:
							pixbuf = PixbufUtility.GetOverlayedRightPixbuf (pixbuf, IconUtility.GetIcon ("galaxium-conversation-active", IconSizes.Small));
							break;
						case ActivityTypes.Transfer:
							pixbuf = PixbufUtility.GetOverlayedRightPixbuf (pixbuf, IconUtility.GetIcon ("galaxium-transfer-receive", IconSizes.Small));
							break;
						default:
							if (contact.Presence != XmppPresence.Online)
							{
								var icon = XmppProtocolFactory.StatusLookup (contact.Presence, IconSizes.Small);
								pixbuf = PixbufUtility.GetOverlayedRightPixbuf (pixbuf, icon);
							}
							break;
					}
				}
				else
				{
					if (contact.Presence != XmppPresence.Online)
					{
						var icon = XmppProtocolFactory.StatusLookup (contact.Presence, IconSizes.Small);
						pixbuf = PixbufUtility.GetOverlayedRightPixbuf (pixbuf, icon);
					}
				}
			}
			
			renderer.Pixbuf = pixbuf;
			renderer.Width = pixbuf.Width;
			renderer.Visible = true;
		}
		
		public override string GetMenuExtensionPoint (object data)
		{
			if (data is XmppConferenceContact)
				return "/Galaxium/Gui/XMPP/ContactTree/ContextMenu/Conference";
			if (data is XmppContact)
				return "/Galaxium/Gui/XMPP/ContactTree/ContextMenu/Contact";
			if (data is ContactTreeRealGroup)
				return "/Galaxium/Gui/XMPP/ContactTree/ContextMenu/Group";
			return base.GetMenuExtensionPoint (data);
		}
				
		public override InfoTooltip GetTooltip (object data)
		{
			if (data is XmppContact)
				return new ContactListTooltip (data as XmppContact);
			
			return base.GetTooltip (data);
		}
		
		public override int Compare (object data1, object data2)
		{
			bool alphabetic = Session.Account.SortAlphabetic;
			
			if (Session.Account.UseDefaultListView)
				alphabetic = Configuration.ContactList.Section.GetBool (Configuration.ContactList.SortAlphabetic.Name,
				                                                        Configuration.ContactList.SortAlphabetic.Default);

			if (data1 is XmppContact && data2 is XmppContact && !alphabetic) {
				XmppContact contact1 = data1 as XmppContact;
				XmppContact contact2 = data2 as XmppContact;
				
				int ret = contact2.Presence.Priority.CompareTo (contact1.Presence.Priority);
				if (ret != 0) return ret;
			}

			return base.Compare (data1, data2);
		}
	}
}
